<?php
/* 
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 * Description of RQLNode
 *
 * @author Admin
 */
class RQLNode {
    public $name;
    public $alias;
    public $operation;
    public $description;
    public $modify;
    public $rid = null;
    public $select_fields = array();
    
    function getName($full = false) {
       if (trim($this->alias)) $name = $this->alias;
       else $name = $this->name;

       if ($full) return  "`$name`";
       return $name;
    }
    function getFilters() {
       $ret = $this->description;
       return $ret;
    }
    function getFilter($field) {
        if (!isset($this->description[$field])) return false;
        return @$this->description[$field];
    }

    function  __construct($name, $alias = null, $operation = null, $description = null, $modify = null) {
        $this->name = $name;
        $this->alias = $alias;
        $this->operation = $operation;
        $this->description = $description;
        $this->modify = $modify;
    }

    public function setName($name) {
        $this->name = $name;
    }

    public function setAlias($name) {
        $this->alias = $name;
    }

    public function setOperation($name) {
        $this->operation = $name;
    }

    public function setDescription($filter) {

        if (is_array($filter)) return;
        $filter = @explode(',', $filter);
        $this->description = array();
        for($i=0;$i<count($filter);$i++) {
            if (preg_match('/(\w+)\s*(=|>|<|!=|>=|<=)\s*(.*)/', $filter[$i], $field_filter)) {
                $this->description[$field_filter[1]]= array(
                    'operator' => trim($field_filter[2]),
                    'value'    => trim($field_filter[3])
                );
            }
        }
    }

    public function setModify($f) {
        $filter = explode(',', $f);
        if (!is_array($filter)) $filter = array($f);
        for($i=0;$i<count($filter);$i++) {
            $field_filter = explode('=', $filter[$i]);
            $this->modify[trim($field_filter[0])] = trim($field_filter[1]);
        }
    }

    public function hasExtendedDescription() {
        if (count($this->description) > 1) return true;
        if (!@$this->description['id']) return false;
        return false;
    }

    public function getFrom($parent = null, $operation = null) {
        $from = array();
        if ($this->rid == null) {
            $this->regenerate_rid();
        }
        if ($parent != null) {
            $from []= 'relations as '.$parent->rid;
        } else {
            $from [] = 'relations as '.$this->rid;
        }
        if ($operation == null) $operation = 'select';
        $check_name = 'must_'.$operation;
        if (method_exists($this, $check_name)) {
            if ($this->$check_name() || $this->hasExtendedDescription() || count($this->select_fields) > 1) {
                $f = '`'.$this->name.'`';
                if ($this->alias != null) $f .= ' as `'.$this->alias.'`';
                $from[] = $f;
            }
        }
        return $from;
    }

    public function must_select() {
        return false !== strpos($this->operation, '$');
    }

    public function must_insert() {
        return false !== strpos($this->operation, '+');
    }

    public function must_delete() {
        return false !== strpos($this->operation, '-');
    }

    public function must_update() {
        if (@isset($this->modify)) return true;
    }

    public function getWhere($parent = null, $acl = 1, $child = null, $operation = null) {
        if ($operation == null) $operation = 'select';
        $operation = 'must_'.$operation;
        $where = array();
        if ($this->rid == null) {
            $this->regenerate_rid();
        }
        if ($parent != null) {
            $id = $this->getFilter('id');
            if ($id != false) {
                $where[] = "{$parent->rid}.child_id {$id['operator']} {$id['value']}";
                if ($this->hasExtendedDescription()||$this->must_select())
                        $where[] = "{$parent->rid}.child_id = {$id['value']}";
            }
            $where[] = "{$parent->rid}.child = '{$this->name}'";
            if ($parent->name) $where[] = "{$parent->rid}.parent = '{$parent->name}'";
            $where[] = "{$parent->rid}.acl & {$acl} = {$acl}";
            $pid = $parent->getFilter('id');
            if ($pid != false) $where[] = "{$parent->rid}.parent_id {$pid['operator']} {$pid['value']}";
            if (method_exists($this, $operation)) {
                if ($this->$operation()) {
                    $where[] = $this->getName().'.id = '.$parent->rid.'.child_id';
                }
            }
        }
        if (is_array($this->description)) {
            foreach ($this->description as $field=>$filter) {
                if ($field == 'id' && $parent != null) {
                    continue;
                } elseif ($field == 'id') {
                    if ($child != null) $where[] = "{$this->rid}.parent_id {$filter['operator']} {$filter['value']}";
                    else {
                        $where[] = "{$this->rid}.child = '{$this->name}'";
                        $where[] = "{$this->rid}.child_id {$filter['operator']} {$filter['value']}";
                    }
                    continue;
                }
                $where[] = "{$this->getName()}.{$field} {$filter['operator']} {$filter['value']}";
            }
        }
        if (count($where)) return implode(' AND ', $where);
        else return true;
    }

    public function getSelect($parent = null, $operation = null) {
        if ($operation == null) $operation = 'select';
        $op = 'must_'.$operation;
        $ret = '';
        if ($this->$op()) {
            if ($operation == 'delete') {
                $ret = "{$parent->rid}.child, ";
                $ret .= "{$parent->rid}.child_id";
            } else {
                if ($parent != null) {
                    $ret = "{$parent->rid}.acl as `###`, ";
                }
                $ret .= $this->getName(true).'.*';
            }
        }
        return $ret;
    }

    public function regenerate_rid() {
        $rid = $this->getName().'_'.rand(1, 10000);
        if ($rid == $this->rid) $this->regenerate_rid();
        else $this->rid = $rid;
    }

    public function getUpdate() {
        $res = array();
        if(!is_array($this->modify)) {
            if (trim($this->modify) == '') return;
            $this->setModify($this->modify);
        }
        foreach($this->modify as $field=>$val) {
            $field = $this->getName().'.'.$field;
            $res[] = "$field = $val";
        }
        return implode(',',$res);
    }

    public function get_real_name($alias) {
        if ($this->alias == $alias || $this->name == $alias) return $this->name;
        return false;
    }

    public function drop_operations_data() {
        $this->operation = '';
    }

    public function get_selected_fields($parent = null, $operation = null) {
        if ($operation == null) $operation = 'select';
        $op = 'must_'.$operation;
        if (count($this->select_fields) == 0 && $this->$op()) return array($this->getSelect($parent, $operation));
        if ($operation != 'select' && $this->$op()) return array($this->getSelect($parent, $operation));
        if (count($this->select_fields) == 0) return array();


        $ret = array();
        foreach($this->select_fields as $field) {
            if($field == 'id') {
                $ret[] = $parent->rid.'.child_id';
            } elseif(preg_match('/\w/', $field)) {
                $ret[] = $this->getName().'.'.$field;
            } else {
                $ret[] = $field;
            }
        }
        if (count($ret) > 0 && $parent != null) {
            array_unshift($ret, $parent->rid.'.acl as `###`');
        }
        return $ret;
    }

    public function get_selected_real_names($parent = null, $operation = null) {
        if ($operation == null) $operation = 'select';
        $op = 'must_'.$operation;
        if ($this->$op()) return $this->name;
        else return array();
    }

    public function drop_selection_data() {
        $this->select_fields = array();
    }

    public function add_selection_field($name) {
        $this->select_fields[] = $name;
    }

    public function update_description_by_real_name($name, $field, $operator, $value) {
        if ($this->name != $name) return false;
        $this->description[$field] = array(
            'operator'=>$operator,
            'value'=>$value
        );
        return true;
    }
    

}
?>